/*
  (C) 2007 - Boston University
  Contact: Michael Ocean 

	this file was adapted from a CS511 submission

  This work is a part of the larger snBench project.  Information
  can be found at: http://csr.bu.edu/snbench 

  This program is free software; you can redistribute it and/or
  modify it under the terms of Version 2 of the GNU General Public 
  License.
  
  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  General Public License for more details.
  
  You should have received a copy of the GNU Library General Public
  License along with this library; if not, write to the Free
  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package stepide;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;

import javax.swing.AbstractListModel;
import javax.swing.JList;
import javax.swing.JTextField;
import javax.swing.ListModel;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;

/**
	Overview: Represents a filtered opcode list supporting type-to-search functionality
*/
public class FilteredOpcodeList extends JList {
	private static final long serialVersionUID = 20070428;
	private FilterField filterField;
	private int DEFAULT_FIELD_WIDTH = 20;

	public FilteredOpcodeList() {
		super();
		setModel(new FilterModel());
		filterField = new FilterField(DEFAULT_FIELD_WIDTH);
	}

	public FilteredOpcodeList(Enumeration<String> elts) {
		super();
		setModel(new FilterModel());
		filterField = new FilterField(DEFAULT_FIELD_WIDTH);
		
		ArrayList<String> list = new ArrayList<String>();
		for(Enumeration e = elts; e.hasMoreElements(); ) {
			list.add((String) e.nextElement());
		}
		Collections.sort(list);
		
		this.addItems(list.toArray());
	}

	public void setModel(ListModel m) {
		if (!(m instanceof FilterModel))
			throw new IllegalArgumentException();
		super.setModel(m);
	}

	public void addItem(Object o) {
		((FilterModel) getModel()).addElement(o);
	}

	public void addItems(Object[] items) {
		((FilterModel) getModel()).addElements(items);
	}

	public JTextField getFilterField() {
		return filterField;
	}
	
	public ArrayList getItemList() {
		return ((FilterModel) getModel()).getItems();
	}

	class FilterModel extends AbstractListModel {
		private static final long serialVersionUID = 20070428;
		private ArrayList items;
		ArrayList filterItems;

		public FilterModel() {
			super();
			items = new ArrayList();
			filterItems = new ArrayList();
		}

		public Object getElementAt(int index) {
			if (index < filterItems.size())
				return filterItems.get(index);
			else
				return null;
		}

		public int getSize() {
			return filterItems.size();
		}
		
		public ArrayList getItems() {
			return items;
		}

		public void addElement(Object o) {
			items.add(o);
			refilter();
		}

		/*
		 * Otherwise refilter gets called each time an object is added on
		 * initial startup (via addElement)!
		 */
		public void addElements(Object[] elements) {
			for (int i = 0; i < elements.length; i++) {
				items.add(elements[i]);
			}
			refilter();
		}

		private void refilter() {
			filterItems.clear();
			String term = getFilterField().getText();
			for (int i = 0; i < items.size(); i++) {
				String itemName = items.get(i).toString();
				String deepestChildItemName = itemName.substring(itemName.lastIndexOf('.') + 1);
				if (deepestChildItemName.startsWith(term)) {
					filterItems.add(items.get(i));
				}
			}
			fireContentsChanged(this, 0, getSize());
		}
	}

	// FilterField inner class listed below

	// inner class provides filter-by-keystroke field
	class FilterField extends JTextField implements DocumentListener {
		private static final long serialVersionUID = 20070428;
		public FilterField(int width) {
			super(width);
			getDocument().addDocumentListener(this);
		}

		public void changedUpdate(DocumentEvent e) {
			((FilterModel) getModel()).refilter();
		}

		public void insertUpdate(DocumentEvent e) {
			((FilterModel) getModel()).refilter();
		}

		public void removeUpdate(DocumentEvent e) {
			((FilterModel) getModel()).refilter();
		}
	}
}